package com.macro.mall.portal.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.macro.mall.common.exception.Asserts;
import com.macro.mall.mapper.UmsAdminMapper;
import com.macro.mall.mapper.UmsMemberLevelMapper;
import com.macro.mall.mapper.UmsMemberMapper;
import com.macro.mall.model.*;
import com.macro.mall.portal.config.WxPayConfig;
import com.macro.mall.portal.domain.MemberDetails;
import com.macro.mall.portal.dto.Code2SessionResult;
import com.macro.mall.portal.dto.MemberUpdateRequest;
import com.macro.mall.portal.service.MpTokenService;
import com.macro.mall.portal.service.UmsMemberCacheService;
import com.macro.mall.portal.service.UmsMemberService;
import com.macro.mall.portal.util.*;
import com.macro.mall.security.util.JwtTokenUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * 会员管理Service实现类 Created by macro on 2018/8/3.
 */
@Service
public class UmsMemberServiceImpl implements UmsMemberService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UmsMemberServiceImpl.class);

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private UmsMemberMapper memberMapper;

    @Autowired
    private UmsMemberLevelMapper memberLevelMapper;

    @Autowired
    private UmsMemberCacheService memberCacheService;

    @Value("${redis.key.authCode}")
    private String REDIS_KEY_PREFIX_AUTH_CODE;

    @Value("${redis.expire.authCode}")
    private Long AUTH_CODE_EXPIRE_SECONDS;

    @Autowired
    private MpTokenService mpTokenService;

    @Autowired
    private UmsAdminMapper umsAdminMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    private MemberUtil memberUtil;

    @Autowired
    private WxPayConfig wxPayConfig;

    @Override
    public UmsMember getByUsername(String username) {
        UmsMember member = memberCacheService.getMember(username);
        if (member != null){
            return member;
        }
        UmsMemberExample example = new UmsMemberExample();
        example.createCriteria().andUsernameEqualTo(username);
        List<UmsMember> memberList = memberMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(memberList)) {
            member = memberList.get(0);
            memberCacheService.setMember(member);
            return member;
        }
        return null;
    }

    @Override
    public UmsMember getById(Long id) {
        return memberMapper.selectByPrimaryKey(id);
    }

    @Override
    public void register(String username, String password, String telephone, String authCode) {
        // 验证验证码
        if (!verifyAuthCode(authCode, telephone)) {
            Asserts.fail("验证码错误");
        }
        // 查询是否已有该用户
        UmsMemberExample example = new UmsMemberExample();
        example.createCriteria().andUsernameEqualTo(username);
        example.or(example.createCriteria().andPhoneEqualTo(telephone));
        List<UmsMember> umsMembers = memberMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(umsMembers)) {
            Asserts.fail("该用户已经存在");
        }
        // 没有该用户进行添加操作
        UmsMember umsMember = new UmsMember();
        umsMember.setUsername(username);
        umsMember.setPhone(telephone);
        umsMember.setPassword(passwordEncoder.encode(password));
        umsMember.setCreateTime(new Date());
        umsMember.setStatus(1);
        // 获取默认会员等级并设置
        UmsMemberLevelExample levelExample = new UmsMemberLevelExample();
        levelExample.createCriteria().andDefaultStatusEqualTo(1);
        List<UmsMemberLevel> memberLevelList = memberLevelMapper.selectByExample(levelExample);
        if (!CollectionUtils.isEmpty(memberLevelList)) {
            umsMember.setMemberLevelId(memberLevelList.get(0).getId());
        }
        // 判断是不是员工
        //获取电话
        Boolean flg = umsAdminMapper.selectByPhone(telephone);
        if (flg) {
        	UmsMember param = new UmsMember();
        	param.setPhone(telephone);
        	Long adminId = memberMapper.getAdminIdByPhone(telephone);
        	if (ObjectUtil.isNotEmpty(adminId)) {
        		param.setAdminId(adminId);
        	}
        	memberMapper.updateIsInternal(param);
        }
        memberMapper.insert(umsMember);
        umsMember.setPassword(null);
    }

    @Override
    public String generateAuthCode(String telephone) {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }
        memberCacheService.setAuthCode(telephone, sb.toString());
        return sb.toString();
    }

    @Override
    public void updatePassword(String telephone, String password, String authCode) {
        UmsMemberExample example = new UmsMemberExample();
        example.createCriteria().andPhoneEqualTo(telephone);
        List<UmsMember> memberList = memberMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(memberList)) {
            Asserts.fail("该账号不存在");
        }
        // 验证验证码
        if (!verifyAuthCode(authCode, telephone)) {
            Asserts.fail("验证码错误");
        }
        UmsMember umsMember = memberList.get(0);
        umsMember.setPassword(passwordEncoder.encode(password));
        memberMapper.updateByPrimaryKeySelective(umsMember);
        memberCacheService.delMember(umsMember.getId());
    }

    @Override
    public UmsMember getCurrentMember() {
        SecurityContext ctx = SecurityContextHolder.getContext();
        Authentication auth = ctx.getAuthentication();
        MemberDetails memberDetails = (MemberDetails) auth.getPrincipal();
        return memberDetails.getUmsMember();
    }

    @Override
    public void updateIntegration(Long id, Integer integration) {
        UmsMember record = new UmsMember();
        record.setId(id);
        record.setIntegration(integration);
        memberMapper.updateByPrimaryKeySelective(record);
        memberCacheService.delMember(id);
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        UmsMember member = getByUsername(username);
        if (member != null) {
            return new MemberDetails(member);
        }
        throw new UsernameNotFoundException("用户名或密码错误");
    }

    @Override
    public String login(String username, String password) {
        String token = null;
        // 密码需要客户端加密后传递
        try {
            UserDetails userDetails = loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
                    null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        } catch (AuthenticationException e) {
            LOGGER.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    @Override
    public String refreshToken(String token) {
        return jwtTokenUtil.refreshHeadToken(token);
    }

    // 对输入的验证码进行校验
    private boolean verifyAuthCode(String authCode, String telephone) {
        if (StrUtil.isEmpty(authCode)) {
            return false;
        }
        String realAuthCode = memberCacheService.getAuthCode(telephone);
        return authCode.equals(realAuthCode);
    }

    @Override
    public Map<String, Object> mpLogin(String codeWx, String codePhone) {
        String token = null;
        UmsMember member = null;
        try {
            Code2SessionResult wxResult = code2Session(codeWx);
            if (!wxResult.isSuccess()) {
                throw new RuntimeException("调用微信接口时发生错误。（" + wxResult.getErrmsg() + "," + wxResult.getErrcode() + "）");
            }
            String openId = wxResult.getOpenid();
            String unionid = wxResult.getUnionid();
            String userPhone = getUserPhoneNumber(codePhone);

            member = getUmsMember(openId, unionid, userPhone);

            UserDetails userDetails = this.loadUserByEntity(member);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
            stringRedisTemplate.opsForValue().set(token, JSONObject.toJSONString(member));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("user", member);

        return map;
    }

    private UmsMember getUmsMember(String openId, String unionid, String userPhone) {
        UmsMember member = memberMapper.getByOpenId(openId);
        if (member == null) {
            member = new UmsMember();
            member.setOpenId(openId);
            member.setPhone(userPhone);
            String userName = userPhone;
            String nickName = userPhone;
            UmsAdmin umsAdmin = umsAdminMapper.getByPhone(userPhone);
            if (umsAdmin != null) {
                userName = umsAdmin.getUsername();
                nickName = umsAdmin.getNickName();
                member.setAdminId(umsAdmin.getId());
                member.setIsInternal(1);
            }
            member.setUsername(userName);
            member.setNickname(nickName);
            memberMapper.addSelective(member);
        }
        member = memberMapper.selectByPrimaryKey(member.getId());
        return member;
    }

    private UserDetails loadUserByEntity(UmsMember member) {
        if (member != null) {
            return new MemberDetails(member);
        }
        throw new UsernameNotFoundException("小程序登录失败");
    }

    private Code2SessionResult code2Session(String wxCode) {
        // 需要修改微信小程序配置信息
        Code2SessionResult code2SessionResult = new Code2SessionResult();
        String url = String.format(MpConstant.MP_JSCODE2_SESSION_URL, wxPayConfig.getAppId(), wxPayConfig.getAppSecret(), wxCode);
        JSONObject json = JSONObject.parseObject(WeChatRequest.callRequestn(url));

        code2SessionResult.setOpenid(String.valueOf(json.get("openid")));
        if (ObjectUtil.isNotEmpty(json.get("unionid")) && StringUtils.isNotEmpty(String.valueOf(json.get("unionid")))) {
            code2SessionResult.setUnionid(String.valueOf(json.get("unionid")));
        }
        code2SessionResult.setSessionKey(String.valueOf(json.get("session_key")));
        code2SessionResult.setErrcode(
                ObjectUtil.isEmpty(json.get("errcode")) ? 0 : Integer.parseInt(String.valueOf(json.get("errcode"))));
        code2SessionResult.setErrmsg(String.valueOf(json.get("errmsg")));

        return code2SessionResult;
    }

    private String getUserPhoneNumber(String code) throws IOException {
        String accessToken = mpTokenService.getAccessToken(wxPayConfig.getAppId(), wxPayConfig.getAppSecret());
        String url = String.format(MpConstant.MP_GETUSERPHONENUMBER_URL, accessToken);

        JSONObject params = new JSONObject();
        params.put("code", code);

        JSONObject json = JSONObject.parseObject(HttpClientUtil.doPostJson(url, null, params));
        if (!json.containsKey("phone_info") || ObjectUtils.isEmpty(json.get("phone_info"))) {
            throw new RuntimeException(json.toJSONString());
        }
        JSONObject phoneInfo = JSONObject.parseObject(json.get("phone_info").toString());
        if (phoneInfo != null && !ObjectUtils.isEmpty(phoneInfo.get("phoneNumber"))) {
            return String.valueOf(phoneInfo.get("phoneNumber"));
        }
        return null;
    }


    //退出
    @Override
    public int mpOut(HttpServletRequest httpRequest){
        try {
            String token = httpRequest.getHeader("Authorization");
            if (token.contains("Bearer ")){
                token = token.replace("Bearer ","").trim();
            }
            String member = stringRedisTemplate.opsForValue().get(token);
            //将用户信息转换成json对象
            JSONObject jsonObject = JSONObject.parseObject(member);
            //根据用户id获取用户信息
            int result = memberMapper.update(Long.valueOf(jsonObject.get("id").toString()));
            stringRedisTemplate.delete(token);
            return result;
        }catch (Exception e){
            return -1;
        }
    }

    @Override
    public int updateInfo(MemberUpdateRequest request,HttpServletRequest httpRequest) {
    	try {
    		UmsMember member = MemberUtils.getUser();
            UmsMember express = new UmsMember();
            express.setIcon(request.getIcon());
            express.setNickname(request.getNickname());
            express.setGender(request.getGender());
            UmsMemberExample example = new UmsMemberExample();
            example.createCriteria().andIdEqualTo(member.getId());
            //获取电话
            String phone = request.getPhone();
            // 判断admin中是不是有电话号码
            Boolean flg = umsAdminMapper.selectByPhone(phone);
            
            int count = memberMapper.updateByExampleSelective(express,example);
            
            if (flg) {
            	UmsMember param = new UmsMember();
            	param.setPhone(phone);
            	Long adminId = memberMapper.getAdminIdByPhone(phone);
            	param.setPhone(phone);
            	if (ObjectUtil.isNotEmpty(adminId)) {
            		param.setAdminId(adminId);
            	}
            	memberMapper.updateIsInternal(param);
            }
            return count;
    	} catch (Exception e) {
			return 0;
		}
        
    }

    @Override
    public UmsMember getInfo() {
        UmsMember entity = MemberUtils.getUser();
        UmsMember umsMember = memberMapper.selectByPrimaryKey(entity.getId());
        UserDetails userDetails = new MemberDetails(umsMember);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
                null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        return umsMember;
    }

}
